﻿using GameFramework.Battle.Core;
using System;
using System.Collections.Generic;
using UnityEngine;
using WorldMapBase;
using Yoozoo.HRP.Runtime;

namespace Yoozoo.Gameplay.RTS
{
#pragma warning disable 0429
    public class ModelInstaning : MonoBehaviour, IModel
    {
        public enum ModelType
        {
            /// <summary>
            /// 步兵
            /// </summary>
            Infantryman,
            /// <summary>
            /// 骑兵
            /// </summary>
            Cavalaryman,
            /// <summary>
            /// 枪兵
            /// </summary>
            Pikeman,
            /// <summary>
            /// 弓兵
            /// </summary>
            Archer
        }

        public int poolKey;
        [Tooltip("Infantryman:步兵\nCavalaryman:骑兵\nPikeman:枪兵\nArcher:弓兵")]
        public Color owner;
        public Color enemy;
        public Material mat;
        public Mesh shadowMesh;
        public Material shadowMat;
        public GPUSkinning_AllBoneAnimation animationInfo;

        public List<Transform> transforms = new List<Transform>();
        public List<Component> components = new List<Component>();
        public Dictionary<string, int> nameToHash;
        //[HideInInspector]
        public Mesh lodMeshLow;
        //[HideInInspector]
        public Mesh lodMeshMedium;

        // 挂点是否已经初始化
        public bool hasInitedMountPoints = false;
        
        public Transform m_transform;
        private GameObject m_gameObject;

        public bool m_displaySubMesh1;
        public bool m_riming;
        public float m_rimInstencity;
        public Color m_rimColor;
        private float m_rimTime = 0.1f;
        private float m_rimSpeed = 10;
        private float m_rimCurTime;
        private float m_sinTime;
        private Action m_endTrigger;
        private float m_startTime;
        private float m_animationLength;
        private bool isPlayTriggerAni;
        private Color _color1 = new Color(59.0f / 255.0f, 159.0f / 255.0f, 255.0f / 255.0f);
        private Color _color2 = new Color(255.0f / 255.0f, 83.0f / 255.0f, 89.0f / 255.0f);
        public bool animatorEnabled = false;
        public bool rendererEnabled = false;
        private int[] paramHashCode;
        public GPUSkinning_SpawnObject m_gpuAnimator;
        int IModel.index { get; set; }
        GameObject IModel.GameObject { get { return m_gameObject; } set { } }
        Transform IModel.Transform { get { return m_transform; } set { } }
        private int m_instancingId;
        float IModel.animatorSpeed
        {
            get { return m_gpuAnimator != null ? m_gpuAnimator.timeScale : 1.0f; }
            set { if (m_gpuAnimator != null) m_gpuAnimator.timeScale = value; }
        }

        private void OnDestroy()
        {
            RemoveSpawnObject();
        }

        static public int ALL_MODEL_INSTANING_COUNTER = 0;
        protected Vector3 position;
        private GameFramework.Battle.Core.EAnimationType currentAnimationType;
        public float localScale = 0.1f;
        private string cullingCameraMark;
        public int CullingLayer => cullingLayer;
        private int cullingLayer;

        public ModelInstaning()
        {
            ALL_MODEL_INSTANING_COUNTER++;
        }

        ~ModelInstaning()
        {
            ALL_MODEL_INSTANING_COUNTER--;
        }

        void OnEnable()
        {
            if (m_gpuAnimator == null)
                return;

            SetAnimatorEnabled(true);
            SetRendererEnabled(true);
        }

        void OnDisable()
        {
            if (m_gpuAnimator == null)
                return;

            SetAnimatorEnabled(false);
            SetRendererEnabled(false);
        }

        public void InitMountPoints(string[] mountPointNames, ref Transform[] mountPoints)
        {
            if (hasInitedMountPoints)
            {
                for (int i = 0; i < mountPointNames.Length; i++)
                {
                    var moutPointTransform = transform.Find(mountPointNames[i]);

                    if (moutPointTransform != null)
                    {
                        mountPoints[i] = moutPointTransform;
                    }
                    else
                    {
                        mountPoints[i] = transform;
#if UNITY_EDITOR
                        BattleDebug.LogError(name + " ModelInstaning InitMountPoints not found mountPoint " + mountPointNames[i]);
#endif
                    }

                }
            }
            else
            {
                for (int i = 0; i < mountPointNames.Length; i++)
                {
                    var mountPoint = new GameObject(mountPointNames[i]);
                    var moutPointTransform = mountPoint.transform;
                    moutPointTransform.SetParent(transform);
                    mountPoints[i] = moutPointTransform;
                }
            }
            hasInitedMountPoints = true;
        }

        public void SetAnimatorEnabled(bool value)
        {
            if (animatorEnabled == value)
                return;

            animatorEnabled = value;
            m_gpuAnimator?.SetAnimatorEnabled(value);
        }
        
        public void SetRendererEnabled(bool value)
        {
            if (rendererEnabled == value)
                return;
        
            rendererEnabled = value;
            m_gpuAnimator?.SetRendererEnabled(value);
        }
        
        public void SetCullingCameraMark(string value)
        {
            cullingCameraMark = value;
        }

        public void SetCullingLayer(int cullingLayer)
        {
            this.cullingLayer = cullingLayer;
        }
        public void SetPosition(Vector3 position)
        {
            this.position = position;
            m_transform.position = position;
            m_gpuAnimator.transformChange = true;
        }

        public Vector3 GetForward()
        {
            return m_transform.forward;
        }
        
        
        public Vector3 GetRotation()
        {
            return m_transform.eulerAngles;
        }


        public void SetScale(float scale, bool saveChange)
        {
            if (saveChange)
            {
                localScale = scale;
            }
            m_transform.localScale = new Vector3(scale,scale,scale);
            m_gpuAnimator.transformChange = true;
        }

        public void ResetScale()
        {
            m_transform.localScale = new Vector3(localScale,localScale,localScale);
            m_gpuAnimator.transformChange = true;
        }

        public void SetRotation(Vector3 eulerAngles)
        {
            m_transform.eulerAngles = eulerAngles;
            m_gpuAnimator.transformChange = true;
        }

        public void SetForward(Vector3 forward)
        {
            if (forward != Vector3.zero)
            {
                m_transform.forward = forward;
                m_gpuAnimator.transformChange = true;
            }

        }
        
        public int SetConfig(int configId, int blockId, int camp,GPUSkinning_AllAnimation allAnimationInfo = null)
        {
            // 防止对象池重复创建
            if (m_gpuAnimator != null)
            {
                return m_instancingId;
            }
            
            shadowMat.SetFloat("_ShadowHeight", GlobalValue.ShadownHeight);
            if (lodMeshMedium==null)
            {
                lodMeshMedium = shadowMesh;
            }
            if (lodMeshLow == null)
            {
                lodMeshLow = shadowMesh;
            }
            int instancingId = GPUInstancingManager.AddInstancingConfig(configId, animationInfo, mat,lodMeshMedium, lodMeshLow,  shadowMat, camp == 1 ? _color1 : _color2,allAnimationInfo);
            m_gpuAnimator = GPUInstancingManager.AddSpawnObject(instancingId, m_transform);
            nameToHash = m_gpuAnimator.paramNameToHash;
            paramHashCode = m_gpuAnimator.paramIndexToHashCode;
            m_displaySubMesh1 = true;

            m_rimColor = Color.black;
            m_riming = false;
            m_rimInstencity = 0;
            SetAnimatorEnabled(true);
            m_instancingId = instancingId;
            return instancingId;
        }


        public void SetMainColor(int instaningId, Color color)
        {
            GPUInstancingManager.SetMainColor(instaningId, color);
        }
        void IModel.OnUpdate()
        {
            var _ct = TimeUtils.GetClientTickTime();
            if (isPlayTriggerAni && _ct - m_startTime >= m_animationLength)
            {
                PlayAttackAnimator();
            }
            if (m_riming)
            {
                if (_ct - m_rimCurTime < m_rimTime)
                {
                    m_sinTime += _ct;
                    m_rimInstencity = (Mathf.Sin(m_sinTime * m_rimSpeed) * 0.5f  + 0.5f) * 10f;
//                    m_rimInstencity = 0.5f;
                    m_gpuAnimator.SetRim(m_instancingId, m_rimColor, 2f, m_rimInstencity);
//                    skinnedMeshRenderer.sharedMaterial.SetFloat("_RimIntensity", rimInstencity);
//                    skinnedMeshRenderer.sharedMaterial.SetColor("_RimColor", m_rimColor);
                }
                else
                {
                    m_riming = false;
                    m_rimInstencity = 0;
                    m_gpuAnimator.SetRim(m_instancingId, m_rimColor, 1, 0);
//                    skinnedMeshRenderer.sharedMaterial.SetFloat("_RimIntensity", 0);
                    m_sinTime = 0;
                }
            }
        }
        public void HideShadow()
        {
            m_displaySubMesh1 = false;
            UEInstanceAnimation ueAnim = GPUInstancingManager.GetInstanceAnimation(m_gpuAnimator);
            if (ueAnim != null)
                ueAnim.MoveChildToLast(m_gpuAnimator);

            //if (m_gpuAnimator != null && m_gpuAnimator.mr != null)
            //{
            //    Material[] mats = m_gpuAnimator.mr.sharedMaterials;
            //    if (mats.Length > 0)
            //    {
            //        m_gpuAnimator.mr.sharedMaterials = new Material[1] { mats[0] };
            //    }
            //}
        }

        public void Init()
        {
            ((IModel)this).OnCreate();
        }

        // private int Uid = 0;
        // public void SetTrigger(string name, int uid)
        // {
        // #if UNITY_EDITOR
        //     if (uid != 0)
        //     {
        //         Uid = uid;
        //     }
        //     UnityEngine.Debug.Log($"Uid = {Uid} SetTrigger {name}");
        // #endif
        //
        //     if (m_gpuAnimator != null)
        //     {
        //         m_gpuAnimator.ResetTrigger();
        //         m_gpuAnimator.SetTrigger(name);
        //     }
        // }
        
        public void SetTrigger(string name,bool resetTransition = false)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.ResetTrigger();
                m_gpuAnimator.SetTrigger(name,resetTransition);
            }
        }

        public void SetAnimatorTime(float time)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.currentTime = time;
            }
        }
        
        void IModel.OnCreate()
        {
            m_transform = transform;
            m_gameObject = gameObject;
            MeshRenderer ren = m_gameObject.GetComponent<MeshRenderer>();
            if (ren != null) UnityEngine.Object.Destroy(ren);
            MeshFilter fil = m_gameObject.GetComponent<MeshFilter>();
            if (fil != null) UnityEngine.Object.Destroy(fil);
            //OnCreateInternal();
        }

        //TODO:不要用名字索引
        Transform IModel.Get(string name)
        {
            for (int i = 0; i < transforms.Count; i++)
            {
                if (transforms[i] != null && name == transforms[i].name)
                {
                    return transforms[i];
                }
            }
            return transform;
        }
        T IModel.Get<T>()
        {
            for (int i = 0; i < components.Count; i++)
            {
                if (components[i].GetType() == typeof(T))
                {
                    return (T)components[i];
                }
            }
            return null;
        }
        void IModel.Gets<T>(ref List<T> list)
        {
            for (int i = 0; i < components.Count; i++)
            {
                if (components[i].GetType() == typeof(T))
                {
                    list.Add((T)components[i]);
                }
            }
        }
        int IModel.InstanceID()
        {
            return gameObject.GetInstanceID();
        }
        void IModel.OnUse()
        {
        }
        void IModel.OnFree()
        {
            //TODO:m_gpuAnimator和ModelInstancing的生命周期应该是一致的,这里只有删除
            //GPUInstancingManager.RemoveSpawnObject(m_gpuAnimator);
            //m_gpuAnimator = null;
        }
        
        void IModel.SetLayer(int layer)
        {
            UEInstanceAnimation ueAnim = GPUInstancingManager.GetInstanceAnimation(m_gpuAnimator);
            if (ueAnim != null)
                ueAnim.SetLayer(layer);
        }
        void IModel.SharedRim(Color color)
        {
            m_riming = true;
            m_rimColor = color;
            m_rimCurTime = TimeUtils.GetClientTickTime();
        }

        void PlayAttackAnimator()
        {
            isPlayTriggerAni = false;
            if (m_endTrigger != null)
            {
                m_endTrigger();
            }
        }
    

        void IModel.SetAnimatorTrigger(EAnimationType tri,bool isReplay,float playSpeed = 1)
        {

            if (m_gpuAnimator != null && (tri != currentAnimationType || isReplay))//
            {
                currentAnimationType = tri;
                m_gpuAnimator.ResetTrigger();
                m_gpuAnimator.SetTrigger(paramHashCode[(int)tri],isReplay,playSpeed);
            }
        }

        float IModel.GetAnimationLength(string aniamtionName, float delValue)
        {
            var animationInfo = GPUInstancingManager.GetInstance().GetAnimation(aniamtionName);

            if (animationInfo == null)
                return delValue;

            return animationInfo.length;
        }

        public void SetAnimatorSpeed(float speed)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetSpeed(speed);
            }
        }

        public void SetAlpha(float alpha)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetAlpha(alpha);
            }
        }
        public void SetCampColor(Color color)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetCampColor(color);
            }    
        }

        public void SetInRoom(float inRoom)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetInRoom(inRoom);
            }
        }

        public void SetBreathLight(float breathLight)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetBreathLight(breathLight);
            }
        }

        public void SetScale(float localScale, float shadowScale = 0)
        {
            throw new NotImplementedException();
        }
        public void SetShadowPosition()
        {

        }

        private void Update()
        {
            if (m_gpuAnimator == null) return;
            m_gpuAnimator.transformChange = true;

            if (!string.IsNullOrEmpty(cullingCameraMark) && rendererEnabled)
            {
                var hCamera = HCameraManager.GetBaseCamera();
                if (!string.IsNullOrEmpty(hCamera.MarkString) && cullingCameraMark.Contains(hCamera.MarkString) && ((hCamera.Camera.cullingMask & (1 << this.cullingLayer))!=0))
                {
                    var baseCamera = hCamera.Camera;
                    var screenPosition = baseCamera.WorldToScreenPoint(transform.position);
                    bool inScreen = !(screenPosition.x > Screen.width + 50 || screenPosition.x < -50 || screenPosition.y > Screen.height + 50 || screenPosition.y < -50);
                    m_gpuAnimator.SetRendererEnabled(inScreen);
                }
                else
                {
                    m_gpuAnimator.SetRendererEnabled(false);
                }
            }
        }
        
        public void SetDissolve(float dissolve)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetDissolveAmount(dissolve);
            }
        }

        public void SetShadowAlpha(float alpha)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetShadowAlpha(alpha);
            }
        }

        public void SetShadowHeight(float height)
        {
            if (m_gpuAnimator!= null)
            {
                m_gpuAnimator.SetShadowHeight(height);
            }
        }
        
        public void OnRelease()
        {
           RemoveSpawnObject();
        }

        private void RemoveSpawnObject()
        {
            if (m_gpuAnimator != null)
            {
                SetAnimatorEnabled(false);
                SetRendererEnabled(false);
                GPUInstancingManager.RemoveSpawnObject(m_gpuAnimator, poolKey);
                m_gpuAnimator = null;
            }
            ResetData();
        }

        private void ResetData()
        {
            rendererEnabled = false;
            animatorEnabled = false;
            m_instancingId = 0;
        }
        
        public float CurrentTime => m_gpuAnimator?.currentTime ?? 0;

        public void SetRimColor(Color color)
        {
            m_rimColor = color;
        }
        
        public void SetRimValue(float rimValue)
        {
            if (m_gpuAnimator != null)
            {
                m_gpuAnimator.SetRim(m_instancingId, m_rimColor, 1, rimValue);
            }
        }

        public Transform GetMountPointByIndex(int index)
        {
            if (!hasInitedMountPoints)
            {
                return null;
            }

            if (m_gpuAnimator == null)
            {
                return null;
            }

            if (m_gpuAnimator.mountPoints.Length <= index)
            {
                UnityEngine.Debug.LogError($"Name = {name},GetMountPointByIndex index = {index} > mountPoints.Length = {m_gpuAnimator.mountPoints.Length}");
                return m_gpuAnimator.mountPoints[0];
            }
            return m_gpuAnimator.mountPoints[index];
        }
    }
}
